package com.adcc.soundalarm.sound;

import com.adcc.soundalarm.common.Log;
import com.adcc.soundalarm.config.system.AlarmFactory;
import com.adcc.soundalarm.config.system.AppConfiguration;
import com.google.common.base.Strings;

import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created by ZHANG on 2017/2/10.
 */
public class SoundAlarm {

    //构造方法私有化
    private SoundAlarm(){}

    /**
     * 静态内部类
     */
    private static class LazyHolder{
        private static final SoundAlarm INSTANCE = new SoundAlarm();
    }

    /**
     * 单例方法
     * */
    public synchronized static SoundAlarm getInstance() {
        return LazyHolder.INSTANCE;
    }

    //告警启动标志
    private boolean startFlag = true;

    //静音标志
    private boolean muteFlag = false;

    // 定时任务
    private ScheduledExecutorService service = null;

    private AlarmRunnable alarmRunnable = new AlarmRunnable();

    /**
     * 声音告警文件播放
     */
    private void playAudioWarn() {
        AlarmFactory alarmFactory = AppConfiguration.getInstance().getAlarmFactory();
        AudioInputStream audioInputStream = null;
        SourceDataLine sourceDataLine = null;
        try {
            AudioFormat audioFormat;
            DataLine.Info dataLine_info;
            if(!Strings.isNullOrEmpty(alarmFactory.getPath())){
                audioInputStream = AudioSystem.getAudioInputStream(new File(alarmFactory.getPath()));
            }
            audioFormat = audioInputStream.getFormat();
            dataLine_info = new DataLine.Info(SourceDataLine.class, audioFormat);
            sourceDataLine = (SourceDataLine) AudioSystem
                    .getLine(dataLine_info);
            byte[] b = new byte[1024];
            int len = 0;
            sourceDataLine.open(audioFormat, 1024);
            sourceDataLine.start();
            while ((len = audioInputStream.read(b)) > 0) {
                sourceDataLine.write(b, 0, len);
            }
            TimeUnit.MILLISECONDS.sleep(500);
        } catch (UnsupportedAudioFileException ex) {
            Log.error("报警音不支持此音频格式 " + ex.toString());
        } catch (IOException ex) {
            Log.error("输入输出流错误 "+ex.toString());
        } catch (LineUnavailableException ex) {
            Log.error("读入行无法取得 "+ex.toString());}
        catch (Exception ex) {
            Log.error("报警间隔失效 "+ex.toString());
        } finally {
            try {
                if(audioInputStream != null){
                    audioInputStream.close();
                }
            } catch (IOException e) {
                Log.error("无法关闭输入流" + e.getMessage());
            }
            if(sourceDataLine != null){
                sourceDataLine.drain();
                sourceDataLine.close();
            }
        }
    }

    /**
     * 开始播放声音告警文件
     */
    public void startAudioWarn() {
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
        if(service == null){
            service = Executors
                    .newSingleThreadScheduledExecutor();
            service.scheduleAtFixedRate(alarmRunnable, 0, 1, TimeUnit.SECONDS);
        }else{
            alarmRunnable.start();
        }
    }

    /**
     * 声音告警文件停止播放
     */
    public void pauseAudioWarn() {
       if(alarmRunnable != null){
           alarmRunnable.pause();
       }
    }

    /**
     * 定时任务停止
     */
    public void dispose(){
        if(service!=null && !service.isShutdown()){
            service.shutdown();
        }
    }

    /**
     * 异步执行线程
     */
    class AlarmRunnable implements Runnable {

        public void pause(){
            startFlag = false;
        }

        public void start(){
            startFlag = true;
        }

        @Override
        public void run() {
            try {
                while (startFlag && !muteFlag){
                    playAudioWarn();
                }
            } catch (Exception ex) {
                Log.error( " AlarmRunnable run() error", ex);
            }
        }
    }

    /**
     * 获取静音标志
     * @return
     */
    public boolean isMuteFlag() {
        return muteFlag;
    }

    /**
     * 静音标志设置
     * @param muteFlag
     */
    public void setMuteFlag(boolean muteFlag) {
        this.muteFlag = muteFlag;
    }
}
